home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 51 / Amiga Format CD51 (2000-03-10)(Future Publishing)(GB)[!][issue 2000-04].iso / -in_the_mag- / workbench / term_4.8 / extras / source / term-source.lha / CustomRequest.c < prev    next >
C/C++ Source or Header  |  1997-07-12  |  19KB  |  796 lines

  1. /*
  2. **    CustomRequest.c
  3. **
  4. **    EasyRequest like custom requester
  5. **
  6. **    Copyright © 1990-1997 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* GetScreenInfo():
  17.      *
  18.      *    Obtain the currently visible screen area.
  19.      */
  20.  
  21. STATIC VOID
  22. GetScreenInfo(struct Screen *Screen,WORD *Left,WORD *Top,WORD *Width,WORD *Height)
  23. {
  24.     struct ViewPortExtra    *Extra;
  25.     struct TagItem             Tags[2] = { VTAG_VIEWPORTEXTRA_GET, NULL, TAG_DONE };
  26.  
  27.     if(!VideoControl(Screen->ViewPort.ColorMap,Tags))
  28.         Extra = (struct ViewPortExtra *)Tags[0].ti_Data;
  29.     else
  30.         Extra = NULL;
  31.  
  32.     if(Extra)
  33.     {
  34.         struct Rectangle Clip;
  35.  
  36.         QueryOverscan(GetVPModeID(&Screen->ViewPort),&Clip,OSCAN_TEXT);
  37.  
  38.         *Width    = Extra->DisplayClip.MaxX - Extra->DisplayClip.MinX + 1;
  39.         *Height    = Extra->DisplayClip.MaxY - Extra->DisplayClip.MinY + 1;
  40.  
  41.         if(*Width < Clip.MaxX - Clip.MinX + 1)
  42.             *Width = Clip.MaxX - Clip.MinX + 1;
  43.  
  44.         if(*Height < Clip.MaxY - Clip.MinY + 1)
  45.             *Height = Clip.MaxY - Clip.MinY + 1;
  46.     }
  47.     else
  48.     {
  49.         *Width    = Screen->Width;
  50.         *Height    = Screen->Height;
  51.     }
  52.  
  53.     *Left    = ABS(Screen->LeftEdge);
  54.     *Top    = ABS(Screen->TopEdge);
  55.  
  56.     if(*Left > Screen->Width || *Left < 0)
  57.         *Left = 0;
  58.  
  59.     if(*Top > Screen->Height || *Top < 0)
  60.         *Top = 0;
  61. }
  62.  
  63.     /* CentreWindow():
  64.      *
  65.      *    Centre a window within the visible bounds of
  66.      *    a screen.
  67.      */
  68.  
  69. STATIC VOID
  70. CentreWindow(struct Screen *Screen,WORD Width,WORD Height,WORD *Left,WORD *Top)
  71. {
  72.     WORD ScreenWidth,ScreenHeight,ScreenLeft,ScreenTop;
  73.  
  74.     GetScreenInfo(Screen,&ScreenLeft,&ScreenTop,&ScreenWidth,&ScreenHeight);
  75.  
  76.     *Left    = ScreenLeft + (ScreenWidth - Width) / 2;
  77.     *Top    = ScreenTop + (ScreenHeight - Height) / 2;
  78. }
  79.  
  80. VOID SAVE_DS ASM
  81. CustomStuffText(REG(a3) LONG *Data,REG(d0) UBYTE Char)
  82. {
  83.     struct IntuiText *IText;
  84.     STRPTR Buffer;
  85.  
  86.     Buffer    = (STRPTR)Data[0];    /* Space allocated for the char buffer */
  87.     IText    = (APTR)Data[1];    /* Space allocated for the IntuiTexts */
  88.  
  89.     if(Char == Data[2] || Char == '\0')
  90.     {
  91.         LONG Width;
  92.  
  93.         IText->LeftEdge    = 0;
  94.         IText->TopEdge    = Data[3];    /* Text top edge */
  95.         IText->ITextFont    = NULL;
  96.  
  97.             /* Line height, derived from font size */
  98.  
  99.         Data[3] += Data[4];
  100.  
  101.             /* Chop off the rest */
  102.  
  103.         *Buffer++ = '\0';
  104.  
  105.             /* Measure the length in pixels */
  106.  
  107.         if(Data[6])
  108.         {
  109.             Width = TextLength((APTR)Data[6],IText->IText,(LONG)Buffer - (LONG)IText->IText - 1);
  110.  
  111.                 /* More than we got before? */
  112.  
  113.             if(Width > Data[5])
  114.                 Data[5] = Width;
  115.         }
  116.  
  117.         if(Char != '\0')
  118.         {
  119.                 /* Link to following text */
  120.  
  121.             IText->NextText = IText + 1;
  122.  
  123.                 /* Get ready for the next line */
  124.  
  125.             Data[1] = (LONG)(++IText);
  126.  
  127.                 /* Start of next line */
  128.  
  129.             IText->IText = Buffer;
  130.         }
  131.         else
  132.             IText->NextText = NULL;            /* Terminate the chain */
  133.     }
  134.     else
  135.         *Buffer++ = Char;                        /* Just store the character */
  136.  
  137.     Data[0] = (LONG)Buffer;                        /* Remember for next char */
  138. }
  139.  
  140. VOID ASM
  141. CustomCountChar(REG(a3) LONG *Count,REG(d0) UBYTE Char)
  142. {
  143.     if(Char == Count[2] || Char == '\0')    /* Count the number of lines */
  144.         Count[1]++;
  145.  
  146.     Count[0]++;                                /* Count the number of characters in total */
  147. }
  148.  
  149. STATIC struct IntuiText *
  150. BuildITextTable(STRPTR FormatString,va_list VarArgs,UBYTE Terminator,LONG *Information,LONG *MoreData)
  151. {
  152.     struct IntuiText *Primitive;
  153.  
  154.     Information[0] = Information[1] = 0;
  155.     Information[2] = Terminator;
  156.  
  157.     #ifdef USE_GLUE
  158.     {
  159.         RawDoFmt(FormatString,(APTR)VarArgs,(PUTCHAR)CustomCountCharGlue,(APTR)Information);
  160.     }
  161.     #else
  162.     {
  163.         RawDoFmt(FormatString,(APTR)VarArgs,(PUTCHAR)CustomCountChar,(APTR)Information);
  164.     }
  165.     #endif
  166.  
  167.     if(Primitive = (struct IntuiText *)AllocVec(Information[1] * sizeof(struct IntuiText) + Information[0],MEMF_ANY))
  168.     {
  169.             /* Room for the char buffer */
  170.  
  171.         MoreData[0]    = (LONG)(Primitive + Information[1]);
  172.  
  173.             /* Room for the IntuiTexts */
  174.  
  175.         MoreData[1] = (LONG)Primitive;
  176.  
  177.             /* Separator char to use */
  178.  
  179.         MoreData[2] = Terminator;
  180.  
  181.             /* Top edge of first text, the following lines get placed below */
  182.  
  183.         MoreData[3] = 0;
  184.  
  185.             /* The maximum width of all lines will end up here */
  186.  
  187.         MoreData[5] = 0;
  188.  
  189.             /* Now this is important; the first IText buffer must */
  190.             /* be set up here, the formatting code will do the rest */
  191.             /* for all the others */
  192.  
  193.         Primitive[0].IText = (STRPTR)MoreData[0];
  194.     }
  195.  
  196.     return(Primitive);
  197. }
  198.  
  199.     /* ShowInfo():
  200.      *
  201.      *    Display an EasyRequest like information requester.
  202.      */
  203.  
  204. LONG
  205. ShowInfo(struct Window *Parent,STRPTR Title,STRPTR Continue,STRPTR FormatString,...)
  206. {
  207.     struct Screen *Screen;
  208.     ULONG IntuiLock;
  209.     LONG Result;
  210.     BOOL PopBack;
  211.  
  212.     Result = 0;
  213.  
  214.     if(Parent)
  215.         Screen = Parent->WScreen;
  216.     else
  217.         Screen = LockPubScreen(NULL);
  218.  
  219.     IntuiLock = LockIBase(NULL);
  220.  
  221.     PopBack = (BOOL)(IntuitionBase->FirstScreen != Screen);
  222.  
  223.     UnlockIBase(IntuiLock);
  224.  
  225.     if(Screen)
  226.     {
  227.         struct DrawInfo *DrawInfo;
  228.  
  229.         if(PopBack)
  230.             ScreenToFront(Screen);
  231.  
  232.         if(DrawInfo = GetScreenDrawInfo(Screen))
  233.         {
  234.             LONG Information[3],GadgetInformation[3];
  235.             LONG MoreData[7],GadgetData[7];
  236.             struct Image *GadgetFrameImage;
  237.             struct IntuiText *GadgetText;
  238.             struct TextAttr FontTemplate;
  239.             struct Gadget **GadgetTable;
  240.             struct IntuiText *BodyText;
  241.             struct TextFont *Font;
  242.             LONG FullButtonWidth;
  243.             LONG DistX,DistY;
  244.             LONG RoomX,RoomY;
  245.             va_list VarArgs;
  246.  
  247.                 /* We'll need this one later */
  248.  
  249.             Font = DrawInfo->dri_Font;
  250.  
  251.                 /* Set up the spacing information */
  252.  
  253.             RoomY = (Font->tf_YSize + 1) / 2;
  254.             RoomX = (RoomY * DrawInfo->dri_Resolution.Y) / DrawInfo->dri_Resolution.X;
  255.  
  256.                 /* Make a copy of the screen font */
  257.  
  258.             AskFont(&Screen->RastPort,&FontTemplate);
  259.  
  260.                 /* Request that it be boldfaced, the leftmost */
  261.                 /* button will receive this type of label */
  262.  
  263.             FontTemplate.ta_Style |= FSF_BOLD;
  264.  
  265.             va_start(VarArgs,FormatString);
  266.             BodyText = BuildITextTable(FormatString,VarArgs,'\n',Information,MoreData);
  267.             va_end(VarArgs);
  268.  
  269.             GadgetText = BuildITextTable(Continue,NULL,'|',GadgetInformation,GadgetData);
  270.  
  271.             GadgetTable = (struct Gadget **)AllocVec(sizeof(struct Gadget *) * GadgetInformation[1],MEMF_ANY|MEMF_CLEAR);
  272.  
  273.             GadgetFrameImage = (struct Image *)NewObjectA(NULL,FRAMEICLASS,NULL);
  274.  
  275.             if(GadgetFrameImage && GadgetTable && GadgetText)
  276.             {
  277.                 struct Gadget *Previous;
  278.                 LONG ID,Last,i;
  279.                 ULONG PrevTag;
  280.  
  281.                 ID            = 0;
  282.                 Last        = GadgetInformation[1] - 1;
  283.  
  284.                 Previous    = NULL;
  285.                 PrevTag        = TAG_IGNORE;
  286.  
  287.                     /* We'll work with the button sizes in a minute... */
  288.  
  289.                 FullButtonWidth = 0;
  290.  
  291.                     /* We don't want fonts to be measured */
  292.  
  293.                 GadgetData[6] = 0;
  294.  
  295.                 #ifdef USE_GLUE
  296.                 {
  297.                     RawDoFmt(Continue,NULL,(PUTCHAR)CustomStuffTextGlue,GadgetData);
  298.                 }
  299.                 #else
  300.                 {
  301.                     RawDoFmt(Continue,NULL,(PUTCHAR)CustomStuffText,GadgetData);
  302.                 }
  303.                 #endif    /* USE_GLUE */
  304.  
  305.                 DistY = 2;
  306.                 DistX = (DistY * DrawInfo->dri_Resolution.Y) / DrawInfo->dri_Resolution.X;
  307.  
  308.                 GadgetText[0].ITextFont = &FontTemplate;
  309.  
  310.                 for(i = 0 ; i <= Last ; i++)
  311.                 {
  312.                     if(i == Last)
  313.                         ID = 0;
  314.                     else
  315.                         ID++;
  316.  
  317.                     GadgetText[i].NextText = NULL;
  318.  
  319.                     if(GadgetTable[i] = NewObject(NULL,FRBUTTONCLASS,
  320.                         GA_IntuiText,    &GadgetText[i],
  321.                         GA_Image,        GadgetFrameImage,
  322.                         GA_RelVerify,    TRUE,
  323.                         GA_ID,            ID,
  324.                         GA_DrawInfo,    DrawInfo,
  325.                         PrevTag,        Previous,
  326.                     TAG_DONE))
  327.                     {
  328.                         Previous    = GadgetTable[i];
  329.                         PrevTag        = GA_Previous;
  330.  
  331.                         SetAttrs(Previous,
  332.                             GA_Width,    2*DistX + Previous->Width,
  333.                             GA_Height,    2*DistY + Previous->Height,
  334.                             GA_DrawInfo,DrawInfo,
  335.                         TAG_DONE);
  336.  
  337.                             /* Add the width of the button, plus */
  338.                             /* some room in between */
  339.  
  340.                         FullButtonWidth += Previous->Width + RoomX;
  341.                     }
  342.                     else
  343.                     {
  344.                         LONG j;
  345.  
  346.                         for(j = 0 ; j < i ; j++)
  347.                             DisposeObject(GadgetTable[i]);
  348.  
  349.                         FreeVec(GadgetTable);
  350.                         GadgetTable = NULL;
  351.  
  352.                         break;
  353.                     }
  354.                 }
  355.  
  356.                     /* Subtract the trailing space, add the border space */
  357.  
  358.                 FullButtonWidth += Screen->WBorRight + RoomX + Screen->WBorLeft;
  359.             }
  360.  
  361.                 /* Did we get what we wanted and will the buttons fit on */
  362.                 /* the screen? */
  363.  
  364.             if(BodyText && GadgetText && GadgetTable && FullButtonWidth <= Screen->Width)
  365.             {
  366.                 WORD WindowWidth,WindowHeight,ScreenWidth,ScreenHeight,ScreenLeft,ScreenTop;
  367.                 struct Image *FillImage,*FrameImage,*TextImage;
  368.                 WORD Width,Height,Left,Top;
  369.                 struct Image *DepthImage;
  370.                 LONG FullTitleWidth;
  371.                 ULONG DepthWidth;
  372.  
  373.                     /* Before we do anything else, set up the */
  374.                     /* full width of the window title; this includes */
  375.                     /* both the text and the depth arrangement gadget */
  376.  
  377.                 if(Title)
  378.                     FullTitleWidth = TextLength(&Screen->RastPort,Title,strlen(Title));
  379.                 else
  380.                     FullTitleWidth = 0;
  381.  
  382.                     /* Get the width of the window depth gadget for this screen */
  383.  
  384.                 if(DepthImage = NewObject(NULL,SYSICLASS,
  385.                     SYSIA_Size,        (Screen->Flags & SCREENHIRES) ? SYSISIZE_MEDRES : SYSISIZE_LOWRES,
  386.                     SYSIA_Which,    DEPTHIMAGE,
  387.                     SYSIA_DrawInfo,    DrawInfo,
  388.                 TAG_DONE))
  389.                 {
  390.                     GetAttr(IA_Width,DepthImage,&DepthWidth);
  391.  
  392.                     DisposeObject(DepthImage);
  393.                 }
  394.                 else
  395.                     DepthWidth = (Screen->Flags & SCREENHIRES) ? 23 : 17;
  396.  
  397.                 FullTitleWidth += DepthWidth + 2;
  398.  
  399.                 if(FullTitleWidth > Screen->Width)
  400.                     FullTitleWidth = Screen->Width;
  401.  
  402.                     /* Increase the size to fit all the buttons into the window */
  403.  
  404.                 if(FullButtonWidth > FullTitleWidth)
  405.                     FullTitleWidth = FullButtonWidth;
  406.  
  407.                     /* Height of each line */
  408.  
  409.                 MoreData[4] = Font->tf_YSize;
  410.  
  411.                     /* Pointer to screen rastport used for measuring the text */
  412.  
  413.                 MoreData[6] = (LONG)&Screen->RastPort;
  414.  
  415.                     /* Now do the magic formatting... */
  416.  
  417.                 va_start(VarArgs,FormatString);
  418.  
  419.                 #ifdef USE_GLUE
  420.                 {
  421.                     RawDoFmt(FormatString,(APTR)VarArgs,(PUTCHAR)CustomStuffTextGlue,(APTR)MoreData);
  422.                 }
  423.                 #else
  424.                 {
  425.                     RawDoFmt(FormatString,(APTR)VarArgs,(PUTCHAR)CustomStuffText,(APTR)MoreData);
  426.                 }
  427.                 #endif    /* USE_GLUE */
  428.  
  429.                 va_end(VarArgs);
  430.  
  431.                     /* The maximum width of all lines is now in MoreData[5], */
  432.                     /* the effective height of the block in MoreData[3]; */
  433.  
  434.                 TextImage = NewObject(NULL,ITEXTICLASS,
  435.                     IA_FGPen,        DrawInfo->dri_Pens[TEXTPEN],
  436.                     IA_Data,        BodyText,
  437.                     IA_Width,        MoreData[5] + 2*DistX,    /* Add a little room around the text */
  438.                     IA_Height,        MoreData[3] + 2*DistY,
  439.                 TAG_DONE);
  440.  
  441.                     /* Build the checkered background fill pattern */
  442.  
  443.                 FillImage = NewObject(NULL,FILLRECTCLASS,
  444.                     IA_APattern,    &Crosshatch,
  445.                     IA_APatSize,    1,
  446.                     IA_Mode,        JAM2,
  447.                     IA_FGPen,        DrawInfo->dri_Pens[SHINEPEN],
  448.                     IA_BGPen,        DrawInfo->dri_Pens[BACKGROUNDPEN],
  449.                 TAG_DONE);
  450.  
  451.                     /* Do the same for the frame around the text */
  452.  
  453.                 FrameImage = NewObject(NULL,FRAMEICLASS,
  454.                     IA_Recessed,    TRUE,
  455.                 TAG_DONE);
  456.  
  457.                     /* Did we get 'em all? */
  458.  
  459.                 if(FillImage && FrameImage && TextImage)
  460.                 {
  461.                     LONG WindowLeft,WindowTop;
  462.                     struct IBox FramedSize;
  463.                     struct Window *Window;
  464.                     struct Gadget Dummy;
  465.  
  466.                         /* We'll need these offsets pretty soon */
  467.  
  468.                     WindowLeft    = Screen->WBorLeft;
  469.                     WindowTop    = Screen->WBorTop + Screen->Font->ta_YSize + 1;
  470.  
  471.                         /* Now check how large the surrounding frame would be */
  472.  
  473.                     DoMethod((Object *)FrameImage,IM_FRAMEBOX,&TextImage->LeftEdge,&FramedSize,DrawInfo,NULL);
  474.  
  475.                         /* Pad the space around the frame a bit */
  476.  
  477.                     FramedSize.Width    += 2 * RoomX;
  478.                     FramedSize.Height    += 2 * RoomY;
  479.  
  480.                         /* Save these for the window open stuff */
  481.  
  482.                     Width    = WindowLeft +    FramedSize.Width +    Screen->WBorRight;
  483.                     Height    = WindowTop +    FramedSize.Height +    Screen->WBorBottom;
  484.  
  485.                         /* If the window title won't fit on the screen, */
  486.                         /* expand the fillimage a bit; do the same to the */
  487.                         /* textimage. */
  488.  
  489.                     if(Width < FullTitleWidth)
  490.                     {
  491.                         LONG Adapt = (FullTitleWidth - Width + 1) & ~1;
  492.  
  493.                         FramedSize.Width    += Adapt;
  494.                         Width                += Adapt;
  495.  
  496.                         DistX                += Adapt / 2;
  497.  
  498.                         SetAttrs((Object *)TextImage,
  499.                             IA_Width,MoreData[5] + 2*DistX,
  500.                         TAG_DONE);
  501.                     }
  502.  
  503.                         /* Adjust size and position of the background pattern */
  504.  
  505.                     SetAttrs((Object *)FillImage,
  506.                         IA_Left,    WindowLeft,
  507.                         IA_Top,        WindowTop,
  508.                         IA_Width,    FramedSize.Width,
  509.                         IA_Height,    FramedSize.Height,
  510.                     TAG_DONE);
  511.  
  512.                         /* Do the whole thing all over again for the framed text; */
  513.                         /* this will put the right coords to centre the text within */
  514.                         /* the frame into FramedSize */
  515.  
  516.                     DoMethod((Object *)FrameImage,IM_FRAMEBOX,&TextImage->LeftEdge,&FramedSize,DrawInfo,FRAMEF_SPECIFY);
  517.  
  518.                         /* Move the text around */
  519.  
  520.                     SetAttrs((Object *)TextImage,
  521.                         IA_Left,    WindowLeft    - FramedSize.Left    + DistX,
  522.                         IA_Top,        WindowTop    - FramedSize.Top    + DistY,
  523.                     TAG_DONE);
  524.  
  525.                         /* Almost finished, now centre the frame around the text */
  526.  
  527.                     DoMethod((Object *)FrameImage,IM_FRAMEBOX,&TextImage->LeftEdge,&FramedSize,DrawInfo,NULL);
  528.  
  529.                     SetAttrs((Object *)FrameImage,
  530.                         IA_Left,    FramedSize.Left        - DistX,
  531.                         IA_Top,        FramedSize.Top        - DistY,
  532.                         IA_Width,    FramedSize.Width,
  533.                         IA_Height,    FramedSize.Height,
  534.                     TAG_DONE);
  535.  
  536.                         /* Now link the objects together */
  537.  
  538.                     FillImage->NextImage    = FrameImage;
  539.                     FrameImage->NextImage    = TextImage;
  540.  
  541.                         /* Zap the dummy gadget and put the image inside */
  542.  
  543.                     memset(&Dummy,0,sizeof(Dummy));
  544.  
  545.                     Dummy.Flags            = GFLG_GADGIMAGE|GFLG_GADGHNONE;
  546.                     Dummy.GadgetRender    = FillImage;
  547.  
  548.                         /* Put the gadget in */
  549.  
  550.                     /* ALWAYS */
  551.                     {
  552.                         LONG LocalLeft    = FrameImage->LeftEdge;
  553.                         LONG LocalTop    = FillImage->TopEdge + FillImage->Height;
  554.  
  555.                         GadgetTable[GadgetInformation[1] - 1]->NextGadget = &Dummy;
  556.  
  557.                         SetAttrs((Object *)FillImage,
  558.                             IA_Height,    FillImage->Height + GadgetTable[0]->Height + RoomY,
  559.                         TAG_DONE);
  560.  
  561.                         Height += GadgetTable[0]->Height + RoomY;
  562.  
  563.                         if(GadgetInformation[1] > 1)
  564.                         {
  565.                             LONG Room,Count,i;
  566.  
  567.                             Room         = Width - FullButtonWidth;
  568.                             Count         = GadgetInformation[1] - 1;
  569.                             LocalLeft     = FrameImage->LeftEdge;
  570.                             Room        += Count * RoomX;
  571.  
  572.                             for(i = 0 ; i <= Count ; i++)
  573.                             {
  574.                                 SetAttrs((Object *)GadgetTable[i],
  575.                                     GA_Top,        LocalTop,
  576.                                     GA_Left,    LocalLeft,
  577.                                 TAG_DONE);
  578.  
  579.                                 LocalLeft += GadgetTable[i]->Width + ((Room * (i + 1)) / Count - (Room * i) / Count);
  580.                             }
  581.                         }
  582.                         else
  583.                         {
  584.                             SetAttrs((Object *)GadgetTable[0],
  585.                                 GA_Top,        LocalTop,
  586.                                 GA_Left,    LocalLeft + (FillImage->Width - GadgetTable[0]->Width) / 2,
  587.                             TAG_DONE);
  588.                         }
  589.                     }
  590.  
  591.                         /* Check if the window will fit on the screen */
  592.  
  593.                     if(Width <= Screen->Width && Height <= Screen->Height)
  594.                     {
  595.                             /* Centre the body text strings */
  596.  
  597.                         /* ALWAYS */
  598.                         {
  599.                             struct IntuiText *This;
  600.  
  601.                             for(This = BodyText ; This ; This = This->NextText)
  602.                             {
  603.                                 This->ITextFont = Screen->Font;
  604.                                 This->LeftEdge = (MoreData[5] - IntuiTextLength(This)) / 2;
  605.                                 This->ITextFont = NULL;
  606.                             }
  607.                         }
  608.  
  609.                             /* Centre the window to open */
  610.  
  611.                         if(Parent)
  612.                         {
  613.                             WindowLeft        = Parent->LeftEdge + Parent->BorderLeft;
  614.                             WindowTop        = Parent->TopEdge + Parent->BorderTop;
  615.                             WindowWidth        = Parent->Width - (Parent->BorderLeft + Parent->BorderRight);
  616.                             WindowHeight    = Parent->Height - (Parent ->BorderTop + Parent->BorderBottom);
  617.  
  618.                             if((Left = WindowLeft + (WindowWidth - Width) / 2) < 0)
  619.                                 Left = 0;
  620.  
  621.                             if((Top = WindowTop + (WindowHeight - Height) / 2) < 0)
  622.                                 Top = 0;
  623.  
  624.                             GetScreenInfo(Screen,&ScreenLeft,&ScreenTop,&ScreenWidth,&ScreenHeight);
  625.  
  626.                             if(Left < ScreenLeft || Left + Width > ScreenLeft + ScreenWidth)
  627.                                 Left = -1;
  628.  
  629.                             if(Top < ScreenTop || Top + Height > ScreenTop + ScreenHeight)
  630.                                 Top = -1;
  631.  
  632.                             if(Top == -1 || Left == -1)
  633.                                 CentreWindow(Screen,Width,Height,&Left,&Top);
  634.                         }
  635.                         else
  636.                             CentreWindow(Screen,Width,Height,&Left,&Top);
  637.  
  638.                             /* Finally, open the window */
  639.  
  640.                         if(Window = OpenWindowTags(NULL,
  641.                             WA_Left,            Left,
  642.                             WA_Top,                Top,
  643.                             WA_Width,            Width,
  644.                             WA_Height,            Height,
  645.                             WA_Title,            Title,
  646.                             WA_Flags,            WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_RMBTRAP | WFLG_NOCAREREFRESH | WFLG_SIMPLE_REFRESH | WFLG_ACTIVATE,
  647.                             WA_IDCMP,            IDCMP_GADGETUP | IDCMP_VANILLAKEY | IDCMP_RAWKEY,
  648.                             WA_CustomScreen,    Screen,
  649.                             WA_Gadgets,            GadgetTable[0],
  650.                         TAG_DONE))
  651.                         {
  652.                             struct IntuiMessage    *Message;
  653.                             struct Gadget *MsgGadget;
  654.                             struct Gadget *Gadget;
  655.                             BOOL Terminated;
  656.                             ULONG MsgClass;
  657.                             LONG MsgCode;
  658.  
  659.                             Gadget        = NULL;
  660.                             Terminated    = FALSE;
  661.  
  662.                             do
  663.                             {
  664.                                 WaitPort(Window->UserPort);
  665.  
  666.                                 while(Message = (struct IntuiMessage *)GetMsg(Window->UserPort))
  667.                                 {
  668.                                     MsgClass    = Message->Class;
  669.                                     MsgCode        = Message->Code;
  670.                                     MsgGadget    = Message->IAddress;
  671.  
  672.                                     ReplyMsg((struct Message *)Message);
  673.  
  674.                                     switch(MsgClass)
  675.                                     {
  676.                                         case IDCMP_GADGETUP:
  677.  
  678.                                             Terminated    = TRUE;
  679.                                             Result        = MsgGadget->GadgetID;
  680.  
  681.                                             break;
  682.  
  683.                                         case IDCMP_VANILLAKEY:
  684.  
  685.                                             MsgCode = ToUpper(MsgCode);
  686.  
  687.                                             switch(MsgCode)
  688.                                             {
  689.                                                 case '\033':
  690.                                                 case 'B':
  691.                                                 case CONTROL_('C'):
  692.  
  693.                                                     Terminated    = TRUE;
  694.                                                     Gadget        = GadgetTable[GadgetInformation[1] - 1];
  695.  
  696.                                                     break;
  697.  
  698.                                                 case '\r':
  699.                                                 case 'V':
  700.  
  701.                                                     Terminated    = TRUE;
  702.                                                     Gadget        = GadgetTable[0];
  703.  
  704.                                                     break;
  705.                                             }
  706.  
  707.                                             break;
  708.  
  709.                                         case IDCMP_RAWKEY:
  710.  
  711.                                             switch(MsgCode)
  712.                                             {
  713.                                                 case HELP_CODE:
  714.  
  715.                                                     GuideDisplay(CONTEXT_MAIN);
  716.                                                     break;
  717.  
  718.                                                 default:
  719.  
  720.                                                     if(MsgCode >= F01_CODE && MsgCode <= F10_CODE)
  721.                                                     {
  722.                                                         MsgCode -= F01_CODE;
  723.  
  724.                                                         if(MsgCode < GadgetInformation[1])
  725.                                                         {
  726.                                                             Terminated = TRUE;
  727.  
  728.                                                             Gadget = GadgetTable[MsgCode];
  729.                                                         }
  730.                                                     }
  731.  
  732.                                                     break;
  733.                                             }
  734.  
  735.                                             break;
  736.                                     }
  737.                                 }
  738.                             }
  739.                             while(!Terminated);
  740.  
  741.                             if(Gadget)
  742.                             {
  743.                                 STATIC ULONG SelectedTags[]        = { GA_Selected,TRUE,    TAG_DONE };
  744.                                 STATIC ULONG DeselectedTags[]    = { GA_Selected,FALSE,    TAG_DONE };
  745.  
  746.                                 SetGadgetAttrsA(Gadget,Window,NULL,(struct TagItem *)SelectedTags);
  747.                                 RefreshGList(Gadget,Window,NULL,1);
  748.  
  749.                                 DelayTime(0,80000);
  750.  
  751.                                 SetGadgetAttrsA(Gadget,Window,NULL,(struct TagItem *)DeselectedTags);
  752.                                 RefreshGList(Gadget,Window,NULL,1);
  753.                             }
  754.  
  755.                             CloseWindow(Window);
  756.                         }
  757.                     }
  758.                 }
  759.  
  760.                     /* Get rid of the images */
  761.  
  762.                 DisposeObject(FillImage);
  763.                 DisposeObject(FrameImage);
  764.                 DisposeObject(TextImage);
  765.             }
  766.  
  767.                 /* And the buffers so much work went into... */
  768.  
  769.             FreeVec(BodyText);
  770.             FreeVec(GadgetText);
  771.  
  772.             if(GadgetTable)
  773.             {
  774.                 LONG i;
  775.  
  776.                 for(i = 0 ; i < GadgetInformation[1] ; i++)
  777.                     DisposeObject(GadgetTable[i]);
  778.  
  779.                 FreeVec(GadgetTable);
  780.             }
  781.  
  782.             DisposeObject(GadgetFrameImage);
  783.  
  784.             FreeScreenDrawInfo(Screen,DrawInfo);
  785.         }
  786.  
  787.         if(PopBack)
  788.             ScreenToBack(Screen);
  789.  
  790.         if(!Parent)
  791.             UnlockPubScreen(NULL,Screen);
  792.     }
  793.  
  794.     return(Result);
  795. }
  796.